package com.nnnu.wsnackshop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nnnu.wsnackshop.exception.ObjectException;
import com.nnnu.wsnackshop.mapper.CategoriesMapper;
import com.nnnu.wsnackshop.mapper.ProductBrandsMapper;
import com.nnnu.wsnackshop.mapper.ProductSkuMapper;
import com.nnnu.wsnackshop.pojo.dto.AddSpuDTO;
import com.nnnu.wsnackshop.pojo.dto.SpuPageDTO;
import com.nnnu.wsnackshop.pojo.dto.UpdateSpuDTO;
import com.nnnu.wsnackshop.pojo.entity.ProductSku;
import com.nnnu.wsnackshop.pojo.entity.ProductSpu;
import com.nnnu.wsnackshop.mapper.ProductSpuMapper;
import com.nnnu.wsnackshop.pojo.entity.Products;
import com.nnnu.wsnackshop.pojo.vo.SpuVO;
import com.nnnu.wsnackshop.result.PageResult;
import com.nnnu.wsnackshop.service.IProductSpuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nnnu.wsnackshop.service.IProductsService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 产品SPU表 服务实现类
 * </p>
 *
 * @author zk
 * @since 2025-05-14
 */
@Service
@RequiredArgsConstructor
public class ProductSpuServiceImpl extends ServiceImpl<ProductSpuMapper, ProductSpu> implements IProductSpuService {

    private final CategoriesMapper catMapper;
    private final ProductBrandsMapper brandMapper;
    private final ProductSkuMapper skuMapper;
    private final IProductsService productService;

    @Override
    public PageResult<SpuVO> pageSpu(@NotNull SpuPageDTO dto) {
        Page<ProductSpu> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        LambdaQueryWrapper<ProductSpu> qw = Wrappers.<ProductSpu>lambdaQuery().like(StrUtil.isNotBlank(dto.getTitle()), ProductSpu::getTitle, dto.getTitle()).eq(dto.getCategoryId() != null, ProductSpu::getCategoryId, dto.getCategoryId()).eq(dto.getBrandId() != null, ProductSpu::getBrandId, dto.getBrandId()).eq(dto.getSaleable() != null, ProductSpu::getSaleable, dto.getSaleable());
        Page<ProductSpu> r = baseMapper.selectPage(page, qw);
        List<SpuVO> vos = r.getRecords().stream().map(spu -> {
            SpuVO vo = BeanUtil.copyProperties(spu, SpuVO.class);
            // 填充额外字段
            vo.setCategoryName(catMapper.selectById(spu.getCategoryId()).getName());
            if (spu.getBrandId() != null) {
                vo.setBrandName(brandMapper.selectById(spu.getBrandId()).getName());
            }
            return vo;
        }).toList();
        return new PageResult<>(r.getTotal(), vos);
    }

    @Override
    public void addSpu(AddSpuDTO dto) {
        ProductSpu spu = BeanUtil.copyProperties(dto, ProductSpu.class);
        baseMapper.insert(spu);
    }

    @Override
    @Transactional
    public void updateSpu(@NotNull UpdateSpuDTO dto) {
        ProductSpu spu = baseMapper.selectById(dto.getId());
        if (spu == null) throw new ObjectException("SPU不存在");
        spu = BeanUtil.copyProperties(dto, ProductSpu.class);
        baseMapper.updateById(spu);
    }

    @Override
    public SpuVO getSpuDetail(Integer id) {
        ProductSpu spu = baseMapper.selectById(id);
        if (spu == null) throw new ObjectException("SPU不存在");
        SpuVO vo = BeanUtil.copyProperties(spu, SpuVO.class);
        vo.setCategoryName(catMapper.selectById(spu.getCategoryId()).getName());
        if (spu.getBrandId() != null) {
            vo.setBrandName(brandMapper.selectById(spu.getBrandId()).getName());
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSpu(List<Integer> ids) {
        // 级联删除 SKU
        baseMapper.deleteBatchIds(ids);
        skuMapper.delete(new LambdaQueryWrapper<ProductSku>().in(ProductSku::getSpuId, ids));
    }

    // --- Excel 导出 / 导入 / 模板 ---
    @Override
    public void exportSpu(HttpServletResponse resp) throws IOException {
        setExcelHeader(resp, "SPU列表");
        try (ExcelWriter writer = EasyExcel.write(resp.getOutputStream(), SpuVO.class).build()) {
            WriteSheet sheet = EasyExcel.writerSheet("SPU").build();
            List<SpuVO> all = baseMapper.selectList(null).stream().map(spu -> {
                SpuVO vo = BeanUtil.copyProperties(spu, SpuVO.class);
                vo.setCategoryName(catMapper.selectById(spu.getCategoryId()).getName());
                return vo;
            }).toList();
            writer.write(all, sheet);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importSpu(@NotNull MultipartFile file) throws IOException {
        List<SpuVO> list = EasyExcel.read(file.getInputStream(), SpuVO.class, null).sheet().doReadSync();
        saveBatch(list.stream().map(vo -> BeanUtil.copyProperties(vo, ProductSpu.class)).toList());
    }

    @Override
    public void downloadSpuTemplate(HttpServletResponse resp) throws IOException {
        setExcelHeader(resp, "SPU导入模板");
        EasyExcel.write(resp.getOutputStream(), SpuVO.class).sheet("模板").doWrite(Collections.emptyList());
    }

    @Override
    public List<SpuVO> listSpuByProduct(Integer productId) {
        if (!productService.exists(new LambdaQueryWrapper<>(Products.class).eq(Products::getId, productId))) {
            return Collections.emptyList();
        }
        // 2. 查询 SPU 列表
        LambdaQueryWrapper<ProductSpu> qw = new LambdaQueryWrapper<ProductSpu>()
                .eq(ProductSpu::getSaleable, true)       // 仅可售
                .eq(ProductSpu::getValid, true)          // 仅有效
                .orderByDesc(ProductSpu::getUpdateTime);
        List<ProductSpu> entities = this.list(qw);
        // 3. 转 VO
        return entities.stream().map(entity -> {
            SpuVO vo = new SpuVO();
            // 假设 SpuVO 字段与实体基本对应
            BeanUtil.copyProperties(entity, vo);
            // 例如设置时间格式化字符串
            vo.setCreateTime(entity.getCreateTime());
            vo.setUpdateTime(entity.getUpdateTime());
            return vo;
        }).collect(Collectors.toList());
    }

    private void setExcelHeader(@NotNull HttpServletResponse resp, String name) {
        String fileName = URLEncoder.encode(name, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        resp.setCharacterEncoding("utf-8");
        resp.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + fileName + ".xlsx");
    }
}
